/*
 * accountsdialog.cpp - dialog with accounts list
 * Copyright (C) 2009  Sergei Stolyarov
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * Kajim::ChatInputText widget implements basic functions required
 * by chat text entry widget: history navigation, autocompletion etc
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <QtGui>
#include <QtDebug>

#include "account.h"
#include "accountstore.h"
#include "accountsdialog.h"
#include "settings.h"
#include "ui/ui_accounts.h"

struct AccountsDialog::Private
{
    Ui::AccountsDialogClass ui;
    QList<Kajim::Account*> deletedAccounts;
};

AccountsDialog::AccountsDialog(QWidget *parent)
    : QDialog(parent)
{
    d = new Private;

    d->ui.setupUi(this);

    createActions();
    restoreGeometry();

    Kajim::AccountStore * store = Kajim::AccountStore::instance();
    // disable tabs widget by default
    d->ui.accountTabs->setEnabled(false);
    // populate accountList widget with account names
    Q_FOREACH (int h, store->accountsList()) {
        Kajim::Account * account = store->account(h);
        QListWidgetItem * item = new QListWidgetItem();
        item->setText(account->param("name"));
        item->setData(AccountsDialog::OriginalAccountDataRole, QVariant::fromValue(account));
        Kajim::Account * clone_account = account->clone();
        item->setData(AccountsDialog::ModifiedAccountDataRole, QVariant::fromValue(clone_account));
        d->ui.accountsList->addItem(item);
    }
    // select first item of the accounts list
    if (d->ui.accountsList->count() > 0) {
        d->ui.accountsList->setCurrentRow(0);
    }
    QIntValidator * portValidator = new QIntValidator(1, 65535, this);
    d->ui.portLineEdit->setValidator(portValidator);
}

AccountsDialog::~AccountsDialog()
{
    delete d;
}

void AccountsDialog::createActions()
{
    connect(d->ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(d->ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    connect(d->ui.addButton, SIGNAL(clicked()), this, SLOT(addAccount()));
    connect(d->ui.removeButton, SIGNAL(clicked()), this, SLOT(removeAccount()));
    connect(d->ui.accountsList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
            this, SLOT(accountsListItemChange(QListWidgetItem*, QListWidgetItem*)));
    connect(d->ui.nameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChange(const QString&)));
    connect(d->ui.jidLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(jidChange(const QString&)));
    connect(d->ui.passwordLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(passwordChange(const QString&)));
    connect(d->ui.resourceLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(resourceChange(const QString&)));
    connect(d->ui.useHostCheckBox, SIGNAL(stateChanged(int)), this, SLOT(useHostChange(int)));
    connect(d->ui.savePassCheckBox, SIGNAL(stateChanged(int)), this, SLOT(savePasswordChange(int)));
    connect(d->ui.hostLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(hostChange(const QString&)));
    connect(d->ui.portLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(portChange(const QString&)));
}

void AccountsDialog::restoreGeometry()
{
    // read splitter position from the config
    QByteArray state = Kajim::Settings::get("accountsdialog/splitter-state").toByteArray();
    if (state != QByteArray()) {
        d->ui.splitter->restoreState(state);
    }
    resize(Kajim::Settings::get("accountsdialog/size").toSize());
    move(Kajim::Settings::get("accountsdialog/pos").toPoint());
}

void AccountsDialog::rememberGeometry()
{
    Kajim::Settings::set("accountsdialog/splitter-state", d->ui.splitter->saveState());
    Kajim::Settings::set("accountsdialog/size", size());
    Kajim::Settings::set("accountsdialog/pos", pos());
}

void AccountsDialog::closeEvent(QCloseEvent * event)
{
    rememberGeometry();
    event->accept();
}

void AccountsDialog::updateCurrentAccountParam(const QString & paramName, const QString & value)
{
    QListWidgetItem * current = d->ui.accountsList->currentItem();
    QVariant data = current->data(AccountsDialog::ModifiedAccountDataRole);
    Kajim::Account * account = data.value<Kajim::Account*>();
    account->setParam(paramName, value);
}

//! \brief Display "Add new account" wizard.
void AccountsDialog::addAccount()
{
    QString name(tr("New Account"));
    QListWidgetItem * item = new QListWidgetItem();
    item->setText(name);
    item->setData(AccountsDialog::OriginalAccountDataRole, 0);
    Kajim::Account * account = new Kajim::Account();
    account->setParam("name", name);
    item->setData(AccountsDialog::ModifiedAccountDataRole, QVariant::fromValue(account));
    d->ui.accountsList->addItem(item);
    // select just added account
    d->ui.accountsList->setCurrentItem(item);
}

//! Delete selected account.
void AccountsDialog::removeAccount()
{
    int row = d->ui.accountsList->currentRow();
    QListWidgetItem * current = d->ui.accountsList->takeItem(row);

    QVariant data = current->data(AccountsDialog::ModifiedAccountDataRole);
    Kajim::Account * modifiedAccount = data.value<Kajim::Account*>();
    delete modifiedAccount;

    data = current->data(AccountsDialog::OriginalAccountDataRole);
    if (data != 0) {
        Kajim::Account * originalAccount = data.value<Kajim::Account*>();
        d->deletedAccounts.append(originalAccount);
    }
}

void AccountsDialog::accountsListItemChange(QListWidgetItem * current, QListWidgetItem *)
{
    QString accountName = current->text();
    QVariant data = current->data(AccountsDialog::ModifiedAccountDataRole);

    Kajim::Account * account = data.value<Kajim::Account*>();
    // enable tabs
    d->ui.accountTabs->setEnabled(true);
    // populate edit entries
    d->ui.nameLineEdit->setText(account->param("name"));
    d->ui.jidLineEdit->setText(account->param("jid"));
    // do not display password
    d->ui.resourceLineEdit->setText(account->param("resource"));
    d->ui.hostLineEdit->setText(account->param("host"));
    d->ui.portLineEdit->setText(account->param("port"));
    Qt::CheckState state;
    if ("true" == account->param("use_host")) {
        state = Qt::Checked;
    } else {
        state = Qt::Unchecked;
    }
    d->ui.useHostCheckBox->setCheckState(state);
    useHostChange(state);

    if ("true" ==  account->param("save_password")) {
        state = Qt::Checked;
    } else {
        state = Qt::Unchecked;
    }
    d->ui.savePassCheckBox->setCheckState(state);
    savePasswordChange(state);
}

void AccountsDialog::nameChange(const QString & text)
{
    QListWidgetItem * current = d->ui.accountsList->currentItem();
    current->setText(text);
    updateCurrentAccountParam("name", text);
}

void AccountsDialog::jidChange(const QString & text)
{
    updateCurrentAccountParam("jid", text);
    // highlight input entry if text is not a valid JID
    QRegExp re("^[^@]+@[^@]+$");
    if (!re.exactMatch(text)) {
        d->ui.jidLineEdit->setStyleSheet("background-color: rgb(255, 145, 145);");
    } else {
        d->ui.jidLineEdit->setStyleSheet(QString());
    }
}

void AccountsDialog::passwordChange(const QString & text)
{
    if (text != "") {
        updateCurrentAccountParam("password", text);
        updateCurrentAccountParam("stored_password", "");
    }
}

void AccountsDialog::resourceChange(const QString & text)
{
    updateCurrentAccountParam("resource", text);
}

void AccountsDialog::useHostChange(int state)
{
    QString text;

    if (Qt::Unchecked == state) {
        // disable host and port entries
        d->ui.hostLineEdit->setEnabled(false);
        d->ui.portLineEdit->setEnabled(false);
        text = "false";
    } else {
        d->ui.hostLineEdit->setEnabled(true);
        d->ui.portLineEdit->setEnabled(true);
        text = "true";
    }
    updateCurrentAccountParam("use_host", text);
}

void AccountsDialog::savePasswordChange(int state)
{
    if (Qt::Unchecked == state) {
        // do not save password, so disable password entry and delete password text
        d->ui.passwordLineEdit->setEnabled(false);
        updateCurrentAccountParam("save_password", "");
        updateCurrentAccountParam("password", "");
    } else {
        d->ui.passwordLineEdit->setEnabled(true);
        updateCurrentAccountParam("save_password", "true");
    }
}


void AccountsDialog::hostChange(const QString & text)
{
    updateCurrentAccountParam("host", text);
}

void AccountsDialog::portChange(const QString & text)
{
    updateCurrentAccountParam("port", text);
}

void AccountsDialog::accept()
{
    // perform checks and save changes
    // TODO: check fields values correctness
    Kajim::AccountStore * store = Kajim::AccountStore::instance();

    int count = d->ui.accountsList->count();
    QStringList names;

    // find duplicates
    for (int i=0; i<count; i++) {
        QListWidgetItem * item = d->ui.accountsList->item(i);
        names.append(item->text());
    }
    QSet<QString> set = names.toSet();
    if (set.count() < count) {
        QMessageBox::warning(this, tr("Warning"), tr("Accounts must have different names!"));
        return;
    }

    // process deletedAccounts list first
    Q_FOREACH(Kajim::Account * account, d->deletedAccounts) {
        store->removeAccount(account);
    }

    for (int i=0; i<count; i++) {
        QListWidgetItem * item = d->ui.accountsList->item(i);
        // TODO: add new items detection code
        QVariant data = item->data(AccountsDialog::ModifiedAccountDataRole);
        Kajim::Account * modifiedAccount = data.value<Kajim::Account*>();

        data = item->data(AccountsDialog::OriginalAccountDataRole);
        if (data != 0) {
            Kajim::Account * originalAccount = data.value<Kajim::Account*>();
            store->updateAccount(originalAccount, modifiedAccount);
        } else {
            Kajim::Account * newAccount = modifiedAccount->clone();
            store->addAccount(newAccount);
        }

        delete modifiedAccount;
    }
    // synchronize
    store->sync();
    // TODO: notify roster window about changes in accounts
    QDialog::accept();
}

void AccountsDialog::reject()
{
    // remove all allocated temporary objects
    int count = d->ui.accountsList->count();
    for (int i=0; i<count; i++) {
        QListWidgetItem * item = d->ui.accountsList->item(i);
        QVariant data = item->data(AccountsDialog::ModifiedAccountDataRole);
        Kajim::Account * modifiedAccount = data.value<Kajim::Account*>();
        delete modifiedAccount;
    }
    QDialog::reject();
}
